package com.fanvil.videoconference;

import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.os.Looper;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import com.fanvil.videoconference.FvlLogger;

public class FvlGLToolbox {
    private static FvlLogger sLogger =
        FvlLogger.getLogger(FvlGLToolbox.class.getSimpleName(), FvlLogger.DEBUG);

    public static int textureNone() {
        sLogger.d("textureNone");
        return 0;
    }

    public static boolean isTexture(int texId) {
        sLogger.d("isTexture");
        return GLES20.glIsTexture(texId);
    }

    public static void deleteTexture(int texId) {
        sLogger.d("deleteTexture: texId=" + texId);
        int[] textures = new int[] { texId };
        assertNonUiThread("glDeleteTextures");
        GLES20.glDeleteTextures(1, textures, 0);
        checkGlError("glDeleteTextures");
    }

    public static int generateTexture() {
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        checkGlError("glGenTextures");
        sLogger.d("generateTexture: texId=" + textures[0]);
        return textures[0];
    }

    public static void setDefaultTexParams() {
        sLogger.d("setDefaultTexParams");
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
                GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
                GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
                GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
                GLES20.GL_CLAMP_TO_EDGE);

        checkGlError("glTexParameter");
    }

    public static int vboNone() {
        sLogger.d("vboNone");
        return 0;
    }

    public static int generateVbo() {
        int[] vbos = new int[1];
        GLES20.glGenBuffers(1, vbos, 0);
        checkGlError("glGenBuffers");
        sLogger.d("generateVbo: vboId=" + vbos[0]);
        return vbos[0];
    }

    public static void setVboData(int vboId, FloatBuffer data, int len) {
        sLogger.d("setVboData");
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
        //GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, len, data, GLES20.GL_STATIC_DRAW);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, len, null, GLES20.GL_STATIC_DRAW);
        GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, len, data);
        checkGlError("glBufferData");
    }

    public static void setVboFloats(int vboId, float[] values) {
        sLogger.d("setVboFloats");
        int len = values.length * 4;
        FloatBuffer buffer = ByteBuffer.allocateDirect(len).order(ByteOrder.nativeOrder()).asFloatBuffer();
        buffer.put(values).position(0);
        setVboData(vboId, buffer, len);
    }

    public static boolean isVbo(int vboId) {
        sLogger.d("isVbo: vboId=" + vboId);
        return GLES20.glIsBuffer(vboId);
    }

    public static void deleteVbo(int vboId) {
        sLogger.d("deleteVbo: vboId=" + vboId);
        int[] buffers = new int[] { vboId };
        GLES20.glDeleteBuffers(1, buffers, 0);
        checkGlError("glDeleteBuffers");
    }

    public static void checkGlError(String operation) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            throw new RuntimeException("GL Operation '" + operation + "' caused error "
                + Integer.toHexString(error) + "!");
        }
    }

    /**
     * Make sure we are not operating in the UI thread.
     *
     * It is often tricky to track down bugs that happen when issuing GL commands in the UI thread.
     * This is especially true when releasing GL resources. Often this will cause errors much later
     * on. Therefore we make sure we do not do these dangerous operations on the UI thread.
     */
    private static void assertNonUiThread(String operation) {
        if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
            throw new RuntimeException("Attempting to perform GL operation '" + operation
                    + "' on UI thread!");
        }
    }
}

